package redis

import (
	"fmt"
	"go2/log"
	"sync"
	"time"

	redis2 "github.com/go-redis/redis"
)

var (
	mpDbMap        map[int]*redis2.Client
	mFuncErrHandle func(error) bool
	mu            sync.RWMutex
)

// Redis配置选项
type Config struct {
	MaxRetries      int
	RetryInterval   time.Duration
	DialTimeout     time.Duration
	ReadTimeout     time.Duration
	WriteTimeout    time.Duration
	PoolSize        int
	MinIdleConns    int
	PoolTimeout     time.Duration
	IdleTimeout     time.Duration
	EnableLog       bool
}

// 默认配置
var DefaultConfig = Config{
	MaxRetries:      5,
	RetryInterval:   2 * time.Second,
	DialTimeout:     5 * time.Second,
	ReadTimeout:     3 * time.Second,
	WriteTimeout:    3 * time.Second,
	PoolSize:        10,
	MinIdleConns:    2,
	PoolTimeout:     4 * time.Second,
	IdleTimeout:     5 * time.Minute,
	EnableLog:       true,
}

func RegistErrHandle(f func(error) bool) {
	mFuncErrHandle = f
}

func RunErrHandle(err error) bool {
	if mFuncErrHandle != nil {
		return mFuncErrHandle(err)
	}
	return false
}

// 线程安全的GetDB
func GetDB(db int) *redis2.Client {
	mu.RLock()
	defer mu.RUnlock()

	if mpDbMap != nil {
		if redisdb, ok := mpDbMap[db]; ok {
			return redisdb
		}
	}
	return nil
}

// 优化的Init函数，支持配置和重试策略
func Init(opt *redis2.Options) bool {
	return InitWithConfig(opt, DefaultConfig)
}

// 带配置的初始化函数
func InitWithConfig(opt *redis2.Options, config Config) bool {
	if opt == nil {
		log.Error("Redis配置不能为空")
		return false
	}

	mu.Lock()
	defer mu.Unlock()

	if mpDbMap == nil {
		mpDbMap = make(map[int]*redis2.Client)
	}

	if _, ok := mpDbMap[opt.DB]; ok {
		return true
	}

	// 应用配置到选项
	applyConfig(opt, config)

	// 使用带有重试机制的连接策略
	redisdb := connectWithRetry(opt, config)
	if redisdb == nil {
		log.Errorf("Redis DB %d 初始化失败", opt.DB)
		return false
	}

	// 测试连接
	if !pingWithRetry(redisdb, config) {
		log.Errorf("Redis DB %d 连接测试失败", opt.DB)
		return false
	}

	mpDbMap[opt.DB] = redisdb
	if config.EnableLog {
		log.Infof("Redis DB %d 初始化成功", opt.DB)
	}
	return true
}

// 应用配置到Redis选项
func applyConfig(opt *redis2.Options, config Config) {
	opt.DialTimeout = config.DialTimeout
	opt.ReadTimeout = config.ReadTimeout
	opt.WriteTimeout = config.WriteTimeout
	opt.PoolSize = config.PoolSize
	opt.MinIdleConns = config.MinIdleConns
	opt.PoolTimeout = config.PoolTimeout
	opt.IdleTimeout = config.IdleTimeout
}

// 带重试的连接策略
func connectWithRetry(opt *redis2.Options, config Config) *redis2.Client {
	var lastErr error

	for i := 0; i < config.MaxRetries; i++ {
		redisdb := redis2.NewClient(opt)
		if redisdb == nil {
			lastErr = fmt.Errorf("redis client creation failed")
			if config.EnableLog {
				log.Errorf("Redis第%d次连接创建失败", i+1)
			}
		} else {
			return redisdb
		}

		if i < config.MaxRetries-1 {
			time.Sleep(config.RetryInterval)
		}
	}

	if config.EnableLog {
		log.Errorf("Redis连接重试耗尽，最后错误: %v", lastErr)
	}
	return nil
}

// 带重试的Ping测试
func pingWithRetry(redisdb *redis2.Client, config Config) bool {
	for i := 0; i < config.MaxRetries; i++ {
		if _, err := redisdb.Ping().Result(); err == nil {
			return true
		} else if config.EnableLog {
			log.Errorf("Redis第%d次Ping测试失败: %v", i+1, err)
		}

		if i < config.MaxRetries-1 {
			time.Sleep(config.RetryInterval)
		}
	}

	return false
}

// 获取所有连接状态
func GetAllStatus() map[int]bool {
	mu.RLock()
	defer mu.RUnlock()

	status := make(map[int]bool)
	for db, client := range mpDbMap {
		if client != nil {
			_, err := client.Ping().Result()
			status[db] = (err == nil)
		} else {
			status[db] = false
		}
	}
	return status
}

// 关闭所有连接
func CloseAll() {
	mu.Lock()
	defer mu.Unlock()

	for db, client := range mpDbMap {
		if client != nil {
			if err := client.Close(); err != nil {
				log.Errorf("关闭Redis DB %d 连接失败: %v", db, err)
			} else if DefaultConfig.EnableLog {
				log.Infof("已关闭Redis DB %d 连接", db)
			}
		}
		delete(mpDbMap, db)
	}
}
